﻿using Framework.Cache;
using Framework.Utility.Extensions;
using Framework.Utility.Helper;
using Framework.Utility.Mail;
using Framework.Utility.ViewModels;
using Hangfire;
using Microsoft.Extensions.Logging;
using Support.Models;
using Support.Models.Entities;
using System.Collections.Generic;
using System.Net.Http;

namespace MonitorCode.Hangfire
{
    public class HangfireService : ServiceConfig, IHangfireService
    {
        private ILogger<HangfireService> _logger;

        private readonly IHttpClientFactory _httpClientFactory;

   
        public HangfireService(ILogger<HangfireService> logger, IHttpClientFactory httpClientFactory)
        {
            _logger = logger;
            _httpClientFactory = httpClientFactory;
        }

        /// <summary>
        /// 获取监控列表
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<TData<List<Job_MonitorServer>>> GetJobFireListAsync(string keyword="")
        {
            var data = await CacheFactory.Cache.GetAsync<List<Job_MonitorServer>>(CacheKay.JobMonitorServer) ?? new List<Job_MonitorServer>();
            var list = data.WhereIf(c=>c.ServerName.Contains(keyword) || c.GroupName.Contains(keyword),!string.IsNullOrWhiteSpace(keyword)).ToList();
            var resultData = new TData<List<Job_MonitorServer>>();
            resultData.data = list;
            resultData.total = list.Count;
            return resultData;
        }
        /// <summary>
        /// 获取监控
        /// </summary>
        /// <param name="jobId"></param>
        /// <returns></returns>
        private async Task<Job_MonitorServer> GetJobFireAsync(string jobId)
        {
            var list = await CacheFactory.Cache.GetAsync<List<Job_MonitorServer>>(CacheKay.JobMonitorServer) ?? new List<Job_MonitorServer>(); 
            return list.FirstOrDefault(c => c.JobId == jobId); 
        }
        /// <summary>
        /// 添加监控
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public TData AddJobFire(Job_MonitorServer model)
        {
            var list = CacheFactory.Cache.Get<List<Job_MonitorServer>>(CacheKay.JobMonitorServer) ?? new List<Job_MonitorServer>();

            if (list.Any(c => c.ServerName == model.ServerName)) return new TData(ResultTag.fail);
            else
            {
                list.Add(model);
                CacheFactory.Cache.Set(CacheKay.JobMonitorServer, list.ToJson());
            }
            return new TData(ResultTag.success);
        }

        /// <summary>
        /// 开启监控
        /// </summary>
        /// <param name="JobId"></param>
        /// <returns></returns>
        public async Task<TData> StartJobFireAsync(string JobId)
        {
            var jobInfo = await GetJobFireAsync(JobId);
            if (jobInfo == null) return new TData(ResultTag.fail);

            var cronExpression = string.IsNullOrWhiteSpace(jobInfo.CronExpression) ? Cron.Minutely() : jobInfo.CronExpression;
      
            RecurringJob.AddOrUpdate(jobInfo.JobId, () => MonitorService(jobInfo), cronExpression, TimeZoneInfo.Local, "default");
            await MonitorService(jobInfo);

            await SetJobFireStatus(JobId, JobFireStatus.Starting);

            return new TData(ResultTag.success);
        }

        /// <summary>
        /// 移除Hangfire
        /// </summary>
        /// <param name="JobId"></param>
        /// <returns></returns>
        public async Task<TData> DeleteJobFireAsync(string? JobId)
        {
            RecurringJob.RemoveIfExists(JobId);
            await SetJobFireStatus(JobId, JobFireStatus.No);
            return new TData(ResultTag.success);
        }

        /// <summary>
        /// 删除监控
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<TData> DeleteServerMonitor(string jobId)
        {
            var list = CacheFactory.Cache.Get<List<Job_MonitorServer>>(CacheKay.JobMonitorServer) ?? new List<Job_MonitorServer>();

            if (!list.Any(c => c.JobId == jobId)) return new TData(ResultTag.fail);
            else
            {
                list.RemoveAll(c => c.JobId == jobId);
                await CacheFactory.Cache.SetAsync(CacheKay.JobMonitorServer, list.ToJson());
            }
            RecurringJob.RemoveIfExists(jobId);
            return new TData(ResultTag.success);
        }

        public async Task MonitorService(Job_MonitorServer model)
        {
            await ExecuteJobAndRetry(model);
        }
        /// <summary>
        /// 获取收件人
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public TData GetReceiveEmail(string jobId)
        {
            var cacheKey = string.Format(CacheKay.JobMonitorReceiveEmail, jobId);
            var data = CacheFactory.Cache.Get<ReceiveEmailConfig>(cacheKey) ?? new ReceiveEmailConfig(); 
            return new TData(ResultTag.success,"", data.ReceiveEmail??string.Empty);
        }
        /// <summary>
        /// 设置收件人
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public TData SetReceiveEmail(ReceiveEmailConfig model)
        {
            var cacheKey = string.Format(CacheKay.JobMonitorReceiveEmail, model.JobId);
            var data = CacheFactory.Cache.Get<ReceiveEmailConfig>(cacheKey) ?? new ReceiveEmailConfig();
            data.JobId = model.JobId;
            data.ReceiveEmail = model.ReceiveEmail;
            CacheFactory.Cache.Set(cacheKey, data.ToJson());
            return new TData(ResultTag.success);
        }
      
        /// <summary>
        /// 异常job处理
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private async Task ExceptionJobFire(Job_MonitorServer model)
        {
            RecurringJob.RemoveIfExists(model.JobId);
            await SetJobFireStatus(model.JobId, JobFireStatus.Exception);

            await SendJobResultEmail(model.JobId, model.ServerName,"Job异常停止");
        }

        /// <summary>
        /// 执行job
        /// 返回 200  返回监控成功，其他返回状态  重试3次 然后 延迟10分钟再执行一次ExecuteJob
        /// </summary>
        /// <param name="model"></param>
        /// <param name="retryTimes"></param>
        /// <returns></returns>
        private async Task ExecuteJobAndRetry(Job_MonitorServer model, int retryTimes = 3)
        {
            if (retryTimes <= 0)
            {
                await ExceptionJobFire(model);
                return;
            }

            string checkPath = model.ServerUrl + model.CheckPath;
            var httpClient = _httpClientFactory.CreateClient(); 
            var result = await httpClient.GetAsync(checkPath).Timeout(3000);
            if (result != null && result.StatusCode == System.Net.HttpStatusCode.OK)
            {
                await SetJobFireStatus(model.JobId, JobFireStatus.Success);
            }
            else
            {
                retryTimes--;
                LogHelper.Error($"ExecuteJob：{checkPath}，剩余重试次数: {retryTimes}, Exception detail: {result?.RequestMessage}");
                await Task.Delay(30000);
                await ExecuteJobAndRetry(model, retryTimes);
            }
        }

        /// <summary>
        /// 修改job 状态
        /// </summary>
        /// <param name="JobId"></param>
        /// <param name="status"></param>
        private async Task SetJobFireStatus(string? JobId, JobFireStatus status)
        {
            var list = await CacheFactory.Cache.GetAsync<List<Job_MonitorServer>>(CacheKay.JobMonitorServer) ?? new List<Job_MonitorServer>();
            var info = list.FirstOrDefault(c => c.JobId == JobId);
            if (info == null) return;
            info.Status = status;
            info.CheckTime = (info.Status == JobFireStatus.Success || info.Status == JobFireStatus.Failure) ? DateTime.Now.ParseToString() : string.Empty;
            await CacheFactory.Cache.SetAsync(CacheKay.JobMonitorServer,list);
        }
    }
}